/** * Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2006-2016 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.glite.security.voms.admin.persistence.dao.hibernate; import java.util.List; import org.apache.commons.lang.Validate; import org.glite.security.voms.admin.persistence.dao.generic.AuditSearchDAO; import org.glite.security.voms.admin.persistence.model.audit.AuditEvent; import org.glite.security.voms.admin.view.actions.audit.AuditLogSearchParams; import org.glite.security.voms.admin.view.actions.audit.AuditLogSearchResults; import org.glite.security.voms.admin.view.actions.audit.ScrollableAuditLogSearchResults; import org.hibernate.Criteria; import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.hibernate.type.StringType; public class AuditSearchDAOHibernate extends GenericHibernateDAO<AuditEvent, Long> implements AuditSearchDAO { AuditSearchDAOHibernate() { } @SuppressWarnings("unchecked") @Override public List<AuditEvent> findLatestEvents(int numEvents) { Validate.isTrue(numEvents >= 0, "numEvents must be a positive integer."); Criteria crit = createCriteria(); crit.addOrder(Order.desc("timestamp")); crit.setMaxResults(numEvents); return crit.list(); } @Override public Integer countEvents() { Criteria crit = createCriteria(); crit.setProjection(Projections.rowCount()); return (Integer) crit.uniqueResult(); } protected Criteria buildCriteriaFromParams(AuditLogSearchParams sp) { Criteria crit = createCriteria(); crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); if (sp.getFromTime() != null) { crit.add(Restrictions.ge("timestamp", sp.getFromTime())); } if (sp.getToTime() != null) { crit.add(Restrictions.le("timestamp", sp.getToTime())); } if (sp.getFilterString() != null && !sp.getFilterString() .trim() .equals("")) { if (sp.getFilterType() .equals(AuditLogSearchParams.FULL_SEARCH_KEY)) { // Full search is basically search over principal // and audit event data point values String filterString = String.format("%%%s%%", sp.getFilterString()); // This is due to another ugly limitation of Hibernate 3.3 // which does not support criteria queries on embedded // collections // See https://hibernate.atlassian.net/browse/HHH-869 crit.add(Restrictions.disjunction() .add(Restrictions.sqlRestriction( "{alias}.event_id in (select ae.event_id from audit_event ae, audit_event_data aed where ae.event_id = aed.event_id and aed.value like ?)", filterString, StringType.INSTANCE)) .add(Restrictions.like("principal", sp.getFilterString() .trim(), MatchMode.ANYWHERE))); } else { crit.add(Restrictions.like(sp.getFilterType(), sp.getFilterString() .trim(), MatchMode.ANYWHERE)); } } if (sp.getFirstResult() != null) { crit.setFirstResult(sp.getFirstResult()); } if (sp.getMaxResults() != null) { crit.setMaxResults(sp.getMaxResults()); } crit.addOrder(Order.desc("timestamp")); return crit; } @SuppressWarnings("unchecked") @Override public AuditLogSearchResults findEventsMatchingParams( AuditLogSearchParams sp) { Criteria crit = buildCriteriaFromParams(sp); List<AuditEvent> results = crit.list(); crit.setProjection(Projections.rowCount()); // This is a workaround for // https://hibernate.atlassian.net/browse/HHH-4761 // TLDR: // The count(*) project doesn't work well with // the limit implementation of the MySQL Hibernate dialect. // Since what we need here is a way to count all results // matching the query in a way that is not relative to the page // size, we can ignore the pagination limits and just set // arbirtray values and the count(*) result will be accurate crit.setFirstResult(0); crit.setMaxResults(100); Long count = (Long) crit.uniqueResult(); if (count == null) { count = 0L; } return new AuditLogSearchResults(sp, count, results); } public ScrollableAuditLogSearchResults scrollEventsMatchingParams( AuditLogSearchParams sp, ScrollMode mode) { Criteria crit = buildCriteriaFromParams(sp); ScrollableResults results = crit.scroll(mode); return new ScrollableAuditLogSearchResults(sp, results); } @Override public Integer countEventsMatchingParams(AuditLogSearchParams sp) { Criteria crit = buildCriteriaFromParams(sp); crit.setProjection(Projections.rowCount()); // This is a workaround for // https://hibernate.atlassian.net/browse/HHH-4761 // TLDR: // The count(*) project doesn't work well with // the limit implementation of the MySQL Hibernate dialect. // Since what we need here is a way to count all results // matching the query in a way that is not relative to the page // size, we can ignore the pagination limits and just set // arbirtray values and the count(*) result will be accurate crit.setFirstResult(0); crit.setMaxResults(100); return (Integer) crit.uniqueResult(); } }